package com.fubowen.lepton.ui.home

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import android.widget.ImageButton
import android.widget.TextView
import androidx.activity.OnBackPressedCallback
import androidx.constraintlayout.widget.ConstraintSet
import androidx.core.view.marginTop
import androidx.core.widget.addTextChangedListener
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.SortedList
import com.fubowen.lepton.R
import com.fubowen.lepton.conf.SiteConfigViewModel
import com.fubowen.lepton.databinding.FragmentHomeBinding
import com.fubowen.lepton.engine.impl.BingSearchEngine
import com.fubowen.lepton.helper.ViewHelper.setConnect
import com.fubowen.lepton.helper.ViewHelper.setVisible
import com.fubowen.lepton.helper.ViewHelper.toast
import com.fubowen.lepton.bean.Suggest
import com.fubowen.lepton.helper.DBHelper
import com.fubowen.lepton.ui.home.suggest.SuggestAdapter
import com.fubowen.lepton.ui.home.suggest.SuggestSortedListAdapterCallback
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlin.system.exitProcess

class HomeFragment : Fragment() {

    private val viewModel: SiteConfigViewModel by activityViewModels()
    private lateinit var binding: FragmentHomeBinding
    private lateinit var clear: ImageButton
    private lateinit var search: EditText
    private lateinit var suggest: RecyclerView
    private lateinit var submit: TextView
    private var top: Int = 0

    private var lastGoBackTime = 0L
    private lateinit var adapter: SuggestAdapter
    private lateinit var suggestList: SortedList<Suggest>
    private lateinit var onBackCallback: OnBackPressedCallback

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentHomeBinding.inflate(inflater, container, false)
        clear = binding.viewSearchClear
        search = binding.viewSearchInput
        top = binding.viewSearchInputContainer.marginTop
        suggest = binding.viewSearchSuggest
        submit = binding.viewSearchSubmit
        adapter = SuggestAdapter()
        val callback = SuggestSortedListAdapterCallback(adapter)
        suggestList = SortedList(Suggest::class.java, callback)
        adapter.setDataSource(suggestList)
        binding.viewSearchSuggest.adapter = adapter
        initSearch()
        initInputPosition()
        goBack()
        return binding.root
    }

    override fun onHiddenChanged(hidden: Boolean) {
        if (hidden) {
            onBackCallback.isEnabled = false
        }
    }

    private fun initSearch() {
        search.addTextChangedListener {
            val hasInput = search.text.isNotBlank()
            clear.setVisible(hasInput)
            if (hasInput) suggest.scrollToPosition(1)
            refreshSuggest(search.text.toString())
        }
        clear.setOnClickListener { search.setText("") }
        search.setOnFocusChangeListener { _, hasFocus ->
            if (hasFocus) {
                viewModel.changeNavigationState(false)
                binding.viewLogo.setVisible(false)
                setBottomToBottomConstraint()
                refreshSuggest("")
            } else {
                closeSearchEditView()
            }
        }
        submit.setOnClickListener {
            val engine = BingSearchEngine()
            val text = search.text.toString()
            if (text.isBlank()) {
                return@setOnClickListener
            }
            CoroutineScope(Dispatchers.IO).launch {
                DBHelper.db.suggestDao().setOrIgnore(
                    Suggest(title = text)
                )
            }
            if (engine.isEnable) {
                return@setOnClickListener
            }
            val url = engine.getUrl(text) ?: ""
            val controller = findNavController()
            val action = HomeFragmentDirections.actionHomeFragmentToSearchListItemDetailFragment(
                text,
                url
            )
            closeSearchEditView()
            controller.navigate(action)
        }
    }

    private fun closeSearchEditView() {
        if (!viewModel.isBottomOfSearchEditText.value) {
            binding.root.setConnect(
                R.id.view_search_input_container,
                ConstraintSet.TOP,
                R.id.view_logo,
                ConstraintSet.BOTTOM,
                top,
                ConstraintSet.BOTTOM
            )
        }
        viewModel.changeNavigationState(true)
        binding.viewLogo.setVisible(true)
        search.clearFocus()
        suggest.setVisible(false)
        search.setText("")
    }

    private fun refreshSuggest(text: String) {
        if (!search.hasFocus()) {
            return
        }
        CoroutineScope(Dispatchers.Main).launch {
            DBHelper.db.suggestDao().all().collect {
                val temp = it.filter { item -> text.isEmpty() || item.title.startsWith(text) }
                if (temp.isNotEmpty()) {
                    suggest.setVisible(true)
                    suggestList.replaceAll(temp)
                } else {
                    suggest.setVisible(false)
                }
            }
        }
    }

    private fun initInputPosition() {
        viewModel.isBottomOfSearchEditText.value.let {
            if (!it) {
                binding.root.setConnect(
                    R.id.view_search_input_container,
                    ConstraintSet.TOP,
                    R.id.view_logo,
                    ConstraintSet.BOTTOM,
                    top,
                    ConstraintSet.BOTTOM
                )
            }
        }
    }

    private fun goBack() {
        viewModel.expandState.observe(viewLifecycleOwner) { onBackCallback.isEnabled = it }
        onBackCallback = object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {
                if (search.hasFocus()) {
                    closeSearchEditView()
                } else {
                    val nextGoBackTime = System.currentTimeMillis()
                    lastGoBackTime = if (lastGoBackTime == 0L) {
                        binding.root.toast(R.string.app_exit, 3000)
                        System.currentTimeMillis()
                    } else {
                        if (nextGoBackTime - lastGoBackTime < 2000) {
                            exitProcess(0)
                        } else {
                            binding.root.toast(R.string.app_exit, 3000)
                            0L
                        }
                    }
                }
            }
        }

        requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, onBackCallback)
    }
    private fun setBottomToBottomConstraint() {
        binding.root.setConnect(
            R.id.view_search_input_container,
            ConstraintSet.BOTTOM,
            R.id.root_layout,
            ConstraintSet.BOTTOM,
            0,
            ConstraintSet.TOP
        )
    }
}
